#!/usr/bin/python3
# -*- coding: UTF-8 -*-

import cantools
from pprint import pprint

class CanFrame:
    def __init__(self):
        self.name = ""
        self.length = 0
        self.canBytes = []
    
    def outputCanFrameCode(self):
        
        bitFlieds = ""
        for byte in self.canBytes:
            bitFlieds += byte.outputCanByteCode()

        sourceCodeform = f"""#include <stdint.h>
struct {self.name + "Frame"}
{{
{bitFlieds}
}};
"""
        return sourceCodeform
    
    def setLength(self, length:int):
        for i in range(length):
            a = CanByte(i)
            self.canBytes.append(a)
    
    def addSignal(self, signal:cantools.database.Signal):
        signalStartBit = signal.start

        startByte = signalStartBit // 8
        startBitInByte = 7 - (signalStartBit % 8)
        remainLength = signal.length
        serialNumber = 0
        isMultibyte = False
        while remainLength > 0:
            lengthInByte = 7 - startBitInByte + 1
            signalName = signal.name
            if (remainLength <= lengthInByte) :
                lengthInByte = remainLength
            else:
                isMultibyte = True
            if True == isMultibyte :
                signalName = signalName + "_" + str(serialNumber)
            self.canBytes[startByte].setBitField(signalName, startBitInByte, lengthInByte)
            startByte += 1
            remainLength -= lengthInByte
            startBitInByte = 0
            serialNumber += 1

    def printBytes(self):
        print(self.name + "\n")
        for byte in self.canBytes:
            byte.printBits()

class CanByte:
    def __init__(self, number):
        self.bits = {0: 'reserved', 1: 'reserved', 2: 'reserved', 3: 'reserved', 4: 'reserved', 5: 'reserved', 6: 'reserved', 7: 'reserved' }
        self.number = number
    
    def outputCanByteCode(self):
        outString = f"//byte {self.number}\n"

        currentSignal = ""
        filedLength = 0
        reservedCount = 0
        for i in range(7, -1, -1) :
            if (currentSignal == self.bits[i]):
                filedLength += 1
                continue
            else:
                if (currentSignal == ""):
                    currentSignal = self.bits[i]
                    filedLength += 1
                    continue

                if (currentSignal == "reserved"):
                    currentSignal += "_" + str(self.number) + "_" + str(reservedCount)
                    reservedCount += 1
                outString += f"\tuint8_t {currentSignal}: {filedLength};\n"
                currentSignal = self.bits[i]
                filedLength = 1

        if (filedLength > 0):
                if (currentSignal == "reserved"):
                    currentSignal += "_" + str(self.number) + "_" + str(reservedCount)
                outString += f"\tuint8_t {currentSignal}: {filedLength};\n"

        return outString
    
    def setBitField(self, name: str, startBit:int, length:int):
        for i in range(0, length):
            self.bits[startBit + i] = name

    def printBits(self):
        print(str(self.number) + "\n")
        pprint(self.bits)
